package com.geek.framework.study.config.microprofile;

import com.geek.framework.study.config.microprofile.source.DefaultResourceConfigSources;
import com.geek.framework.study.config.microprofile.source.JavaSystemEnvironmentConfigSource;
import com.geek.framework.study.config.microprofile.source.OperationSystemEnvironmentConfigSource;
import org.eclipse.microprofile.config.spi.ConfigSource;

import java.util.*;
import java.util.function.Consumer;


public class ConfigSources implements Iterable<ConfigSource> {

    private List<ConfigSource> configSourceList = new LinkedList<>();

    private volatile boolean addedDefaultConfigSources;
    private volatile boolean addedDiscoveredConfigSources;

    private ClassLoader classLoader;

    public ConfigSources(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public void addDefaultSources() {
        if (addedDefaultConfigSources) {
            return ;
        }
        addConfigSources(JavaSystemEnvironmentConfigSource.class,
                OperationSystemEnvironmentConfigSource.class,
                DefaultResourceConfigSources.class);
        addedDefaultConfigSources = true;
    }

    public void addDiscoveredSources() {
        if (addedDiscoveredConfigSources) {
            return;
        }
        ServiceLoader<DefaultResourceConfigSources> configSources = ServiceLoader.load(DefaultResourceConfigSources.class, classLoader);
        for (DefaultResourceConfigSources configSource : configSources) {
            configSourceList.add(configSource);
        }
        sort();
        addedDiscoveredConfigSources = true;
    }




    public void addConfigSources(Class<? extends ConfigSource>... configClasses) {
        for (Class aClass : configClasses) {
            configSourceList.add(newInstance(aClass));
        }
        sort();
    }

    void addConfiSource(ConfigSource... configSources) {
        for (ConfigSource configSource : configSources) {
            configSourceList.add(configSource);
        }
    }

    private void sort() {
        configSourceList.sort(Comparator.comparingInt(ConfigSource::getOrdinal));
    }

    private ConfigSource newInstance(Class<? extends ConfigSource> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public Iterator<ConfigSource> iterator() {
        return configSourceList.iterator();
    }

    @Override
    public void forEach(Consumer<? super ConfigSource> action) {
        configSourceList.forEach(action);
    }

    @Override
    public Spliterator<ConfigSource> spliterator() {
        return configSourceList.spliterator();
    }

}
